﻿/**
 * @file lv_watch_common.c
 *
 */

/*********************
 *      INCLUDES
 *********************/
#include "lv_watch.h"

#if USE_LV_WATCH_COMMON != 0

#include <stdio.h>

/*********************
 *      DEFINES
 *********************/
#define FEBRUARY            2
#define STARTOFTIME         1970
#define SECDAY              86400L                                           // seconds per day
#define LEAP_YEAR(year)     ((year) % 4 == 0)
#define DAYS_IN_YEAR(a)     (LEAP_YEAR(a) ? 366 : 365)
#define DAYS_IN_MONTH(a)    (month_days[(a) - 1])

/**********************
 *  STATIC VARIABLES
**********************/
static int32_t month_days[12] = {
    31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};

static lv_signal_cb_t ancestor_scrl_signal;

/**********************
 *      TYPEDEFS
 **********************/
typedef struct {
    lv_cont_ext_t old_ext;
    lv_obj_t * lable;
    lv_point_t point_list[2];
} lv_watch_common_ext_t;

/**********************
 *  STATIC PROTOTYPES
 **********************/

/**********************
 *  STATIC VARIABLES
 **********************/

/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/
const void * lang_get_text_by_id(uint16_t txtId)
{
#if LV_USE_MULTI_LANG
    if(lv_lang_act() == LANG_CH) { /*0--En, 1--Ch, 2--Ar*/
        return(lang_get_chinese_text(txtId));
    #if USE_LV_WATCH_LANG_ARABIC != 0
    } else if(lv_lang_act() == LANG_AR) {
        return(lang_get_arabic_text(txtId));
    #endif
    } else {
        return(lang_get_english_text(txtId));
    }
#else
    return(lv_lang_get_text(txtId));
#endif
}

void lv_obj_set_y_animation(lv_obj_t * obj, lv_coord_t y, bool anim_en, uint16_t anim_time, void (*cb)(lv_anim_t *))
{
#if LV_USE_ANIMATION == 0
    anim_en = false;
#endif
    if(anim_time == 0 || anim_en == false) {
        lv_obj_set_y(obj, y);
    } else {
#if LV_USE_ANIMATION
        lv_anim_path_t path;
        lv_anim_path_init(&path);
        lv_anim_path_set_cb(&path, lv_anim_path_linear);
        lv_anim_t a;
        lv_anim_init(&a);
        lv_anim_set_var(&a, obj);
        lv_anim_set_values(&a,  lv_obj_get_y(obj), y);
        lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_obj_set_y);
        lv_anim_set_ready_cb(&a,(lv_anim_ready_cb_t)cb);
        lv_anim_set_time(&a, anim_time);
        lv_anim_set_delay(&a, 0);
        lv_anim_set_repeat_count(&a, 0);
        lv_anim_set_path(&a, &path);
        lv_anim_start(&a);
#endif
    }
}

void lv_obj_set_x_animation(lv_obj_t * obj, lv_coord_t x, bool anim_en, uint16_t anim_time, void (*cb)(lv_anim_t *))
{
#if LV_USE_ANIMATION == 0
    anim_en = false;
#endif
    if(anim_time == 0 || anim_en == false) {
        lv_obj_set_x(obj, x);
    } else {
#if LV_USE_ANIMATION
        lv_anim_path_t path;
        lv_anim_path_init(&path);
        lv_anim_path_set_cb(&path, lv_anim_path_linear);
        lv_anim_t a;
        lv_anim_init(&a);
        lv_anim_set_var(&a, obj);
        lv_anim_set_values(&a,  lv_obj_get_x(obj), x);
        lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_obj_set_x);
        lv_anim_set_ready_cb(&a,(lv_anim_ready_cb_t)cb);
        lv_anim_set_time(&a, anim_time);
        lv_anim_set_delay(&a, 0);
        lv_anim_set_repeat_count(&a, 0);
        lv_anim_set_path(&a, &path);
        lv_anim_start(&a);
#endif
    }
}

lv_obj_t * lv_watch_cont_create(lv_obj_t * par, lv_align_t cont_layout, lv_style_t * style, lv_coord_t width)
{
    lv_obj_t * content = lv_cont_create(par, NULL);
    lv_cont_set_fit2(content, LV_FIT_NONE, LV_FIT_TIGHT);
    lv_obj_set_width(content, width);
    lv_obj_add_style(content, LV_OBJ_PART_MAIN, style);
    lv_cont_set_layout(content, cont_layout);
    lv_obj_set_click(content, false);
    return content;
}

#ifdef LV_MEM_USER_DEBUG
void watch_ui_mem_dump(void * para)
{
    lv_task_enable(false);
    Hal_Mem_Record_Dump(true);
    exit(1);
}

void watch_ui_destroy_obj(void * para)
{
    static uint8_t i = 0;
    Hal_Mem_Record_Dump(false);

    if(i++ == 4){
        lv_watch_go_home();

        lv_obj_t * act_obj = lv_watch_get_activity_obj(ACT_ID_LAUNCHER);
        if(act_obj) {
            lv_watch_activity_ext_t * ext = lv_obj_get_ext_attr(act_obj);
            if(ext) ext->prepare_destory(act_obj);
        }

        lv_img_cache_invalidate_src(NULL);
        lv_obj_del(lv_scr_act());
        lv_async_call(watch_ui_mem_dump, NULL);
    }
}
#endif

/* draw track of the pointer */
static void pointer_test_event_cb(lv_obj_t * obj, lv_event_t e)
{
    char xy_value[40];
    lv_watch_common_ext_t * common_ext = lv_obj_get_ext_attr(obj);
    lv_point_t * point_list = common_ext->point_list;

    if(LV_EVENT_PRESSED == e) {
        lv_obj_t * childobj = lv_obj_get_child(obj, NULL);

        while(childobj) {
            lv_obj_del(childobj);
            childobj = lv_obj_get_child(obj, NULL);
        }

        lv_indev_t * indev = lv_indev_get_act();
        lv_indev_get_point(indev, point_list);

        // draw dot
        lv_obj_t * arc = lv_arc_create(obj, NULL);
        lv_arc_set_angles(arc, 0, 0);
        lv_obj_set_size(arc, 2, 2);
        lv_obj_set_pos(arc, point_list[0].x, point_list[0].y);
        lv_obj_set_click(arc, false);

        common_ext->lable = lv_label_create(obj, NULL);
        snprintf(xy_value, 40, "x:%u, y:%u", point_list[0].x, point_list[0].y);
        lv_label_set_text(common_ext->lable, xy_value);
        lv_obj_align(common_ext->lable, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 5);
    } else if(LV_EVENT_PRESSING == e) {
        lv_indev_t * indev = lv_indev_get_act();
        lv_indev_get_point(indev, &point_list[1]);

        if((point_list[0].x != point_list[1].x)
                || (point_list[0].y != point_list[1].y)) {
            // draw dot
            lv_obj_t * arc = lv_arc_create(obj, NULL);
            lv_arc_set_angles(arc, 0, 0);
            lv_obj_set_size(arc, 2, 2);
            lv_obj_set_pos(arc, point_list[1].x, point_list[1].y);
            lv_obj_set_click(arc, false);

            snprintf(xy_value, 40, "x:%u, y:%u", point_list[1].x, point_list[1].y);

            lv_label_set_text(common_ext->lable, xy_value);
            memcpy(point_list, &point_list[1], sizeof(lv_point_t));
        }
    } else if(LV_EVENT_CLICKED == e) {
        lv_indev_t * indev = lv_indev_get_act();
        lv_indev_get_point(indev, &point_list[1]);

        // draw dot
        lv_obj_t * arc = lv_arc_create(obj, NULL);
        lv_arc_set_angles(arc, 0, 0);
        lv_obj_set_size(arc, 2, 2);
        lv_obj_set_pos(arc, point_list[1].x, point_list[1].y);
        lv_obj_set_click(arc, false);

        snprintf(xy_value, 40, "x:%u, y:%u", point_list[1].x, point_list[1].y);

        lv_label_set_text(common_ext->lable, xy_value);

        #ifdef LV_MEM_USER_DEBUG
        lv_async_call(watch_ui_destroy_obj, NULL);
        #endif
    }
}

void btn_event_cb(lv_obj_t * btn_obj, lv_event_t e)
{
    if(LV_EVENT_CLICKED == e)
    {
        lv_watch_png_cache_all_free();

        lv_obj_t * child_obj = lv_watch_obj_create(NULL);
        LV_ASSERT_MEM(child_obj);
        if(child_obj == NULL) return;
        lv_watch_obj_set_anim_mode(child_obj, LV_WATCH_ANIM_HOR_RIGHT_HIDE);

        lv_obj_t * content = lv_cont_create(child_obj, NULL);
        lv_obj_add_style(content, LV_OBJ_PART_MAIN, &lv_style_pretty);
        lv_obj_set_style_local_bg_color(content, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
        lv_obj_set_style_local_bg_grad_color(content, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);

        lv_obj_set_size(content, lv_obj_get_width(child_obj), lv_obj_get_height(child_obj) / 2);
        lv_obj_align(content, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
        lv_obj_set_event_cb(content, pointer_test_event_cb);
        lv_obj_set_click(content, true);
        lv_obj_allocate_ext_attr(content, sizeof(lv_watch_common_ext_t));
        dial_test();
    }
}

/* return ms, str is string of the hour:minte:second */
uint32_t lv_watch_time_elaps(uint32_t last_tick, char * str, int8_t size)
{
    uint32_t elaps = lv_tick_elaps(last_tick);
    uint32_t seconds = tick_to_ms(elaps) / 1000;
    uint32_t minutes = seconds / 60;
    seconds = seconds % 60;
    uint32_t hours = minutes / 60;
    minutes = minutes % 60;

    //printf("lv_watch_time_elaps: elaps=%d, hours=%d, minutes=%d, seconds=%d\n", elaps, hours, minutes, seconds);

    if(hours == 0) {
        if(lv_lang_act() == LANG_CH) {
            snprintf(str, size, "%d分:%d秒", minutes, seconds);
        } else {
            snprintf(str, size, "%d:%d", minutes, seconds);
        }
    } else {
        if(lv_lang_act() == LANG_CH) {
            snprintf(str, size, "%d时:%d分:%d秒", hours, minutes, seconds);
        } else {
            snprintf(str, size, "%d:%d:%d", hours, minutes, seconds);
        }
    }

    return tick_to_ms(elaps);
}

#if 0
void lv_watch_obj_png_release(lv_obj_t * obj)
{
    /* although hidden, release it*/
    //if(lv_obj_get_hidden(obj)) return;

    /*Recursively search the children*/
    lv_obj_t * i;
    lv_obj_t * i_next;
    i = lv_ll_get_head(&(obj->child_ll));

    while(i != NULL) {
        /*Get the next object*/
        i_next = lv_ll_get_next(&(obj->child_ll), i);

        /*another is img btn*/
        lv_obj_type_t obj_type;
        lv_obj_get_type(i, &obj_type);
        printf("obj type =%s\n", *obj_type.type);
        if(!strcmp((*obj_type.type), "lv_img")) {
            lv_watch_img_png_release(i);
        } else if(!strcmp((*obj_type.type), "lv_imgbtn")) {
            lv_watch_imgbtn_png_release(i);
        }

        /*Call the recursive search to the child too*/
        lv_watch_obj_png_release(i);

        /*Set i to the next node*/
        i = i_next;
    }
}

void lv_watch_img_png_release(lv_obj_t * img)
{
    /*Extend the basic object to image object*/
    lv_img_ext_t * ext = lv_obj_allocate_ext_attr(img, sizeof(lv_img_ext_t));
    lv_mem_assert(ext);
    if(ext == NULL) return;
    if(ext->src_type != LV_IMG_SRC_VARIABLE) return;

#if USE_LV_ANIMATION
    lv_anim_del(img, NULL);
#endif

    lv_watch_png_free(lv_img_get_src(img));
}

void lv_watch_imgbtn_png_release(lv_obj_t * imgbtn)
{
#if USE_LV_ANIMATION
    lv_anim_del(imgbtn, NULL);
#endif

    /*Extend the basic object to image object*/
#if LV_IMGBTN_TILED == 0
    lv_watch_png_free(lv_imgbtn_get_src(imgbtn, LV_IMGBTN_STYLE_REL));
    lv_watch_png_free(lv_imgbtn_get_src(imgbtn, LV_IMGBTN_STYLE_PR));
    lv_watch_png_free(lv_imgbtn_get_src(imgbtn, LV_IMGBTN_STYLE_TGL_REL));
    lv_watch_png_free(lv_imgbtn_get_src(imgbtn, LV_IMGBTN_STYLE_TGL_PR));
    lv_watch_png_free(lv_imgbtn_get_src(imgbtn, LV_IMGBTN_STYLE_INA));
#else
    lv_watch_png_free(lv_imgbtn_get_src_left(imgbtn, LV_IMGBTN_STYLE_REL));
    lv_watch_png_free(lv_imgbtn_get_src_left(imgbtn, LV_IMGBTN_STYLE_PR));
    lv_watch_png_free(lv_imgbtn_get_src_left(imgbtn, LV_IMGBTN_STYLE_TGL_REL));
    lv_watch_png_free(lv_imgbtn_get_src_left(imgbtn, LV_IMGBTN_STYLE_TGL_PR));
    lv_watch_png_free(lv_imgbtn_get_src_left(imgbtn, LV_IMGBTN_STYLE_INA));

    lv_watch_png_free(lv_imgbtn_get_src_middle(imgbtn, LV_IMGBTN_STYLE_REL));
    lv_watch_png_free(lv_imgbtn_get_src_middle(imgbtn, LV_IMGBTN_STYLE_PR));
    lv_watch_png_free(lv_imgbtn_get_src_middle(imgbtn, LV_IMGBTN_STYLE_TGL_REL));
    lv_watch_png_free(lv_imgbtn_get_src_middle(imgbtn, LV_IMGBTN_STYLE_TGL_PR));
    lv_watch_png_free(lv_imgbtn_get_src_middle(imgbtn, LV_IMGBTN_STYLE_INA));

    lv_watch_png_free(lv_imgbtn_get_src_right(imgbtn, LV_IMGBTN_STYLE_REL));
    lv_watch_png_free(lv_imgbtn_get_src_right(imgbtn, LV_IMGBTN_STYLE_PR));
    lv_watch_png_free(lv_imgbtn_get_src_right(imgbtn, LV_IMGBTN_STYLE_TGL_REL));
    lv_watch_png_free(lv_imgbtn_get_src_right(imgbtn, LV_IMGBTN_STYLE_TGL_PR));
    lv_watch_png_free(lv_imgbtn_get_src_right(imgbtn, LV_IMGBTN_STYLE_INA));
#endif
}

void lv_watch_png_free(const void * img_src)
{
    if(!img_src) return;

    lv_img_header_t header;
    lv_img_dsc_get_info((char *)img_src, &header);
    if(header.cf != LV_IMG_CF_RAW_ALPHA) return;

#ifdef USE_LV_DRAW_IMG_PNG_DECODER
    //printf("lv_watch_png_free, img_src= %p\n", img_src);
    png_decoder_close_img_buf(img_src);
#endif
}
#endif

void lv_watch_png_cache_all_free(void)
{
    //lv_img_cache_invalidate_src(NULL); // clear all img in cache including jpeg and png
}

void lv_watch_get_child_obj(lv_obj_t * par, lv_signal_cb_t child_signal_func, lv_obj_t ** child_obj)
{
    /*Recursively search the children*/
    lv_obj_t * i;
    lv_obj_t * i_next;
    i = _lv_ll_get_head(&(par->child_ll));

    while(i != NULL) {
        /*Get the next object*/
        i_next = _lv_ll_get_next(&(par->child_ll), i);

        /*another is img btn*/
        if(lv_obj_get_signal_cb(i) == child_signal_func) {
            //printf("lv_watch_get_child_obj=%p\n", i);
            *child_obj = i;
            break;
        }

        /*Call the recursive search to the child too*/
        lv_watch_get_child_obj(i, child_signal_func, child_obj);

        /*Set i to the next node*/
        i = i_next;
    }
}

void lv_watch_get_parent_obj(lv_obj_t * element, lv_signal_cb_t par_signal_func, lv_obj_t ** par_obj)
{
    lv_obj_t * parent_obj = lv_obj_get_parent(element);
    while(parent_obj) {
        if(lv_obj_get_signal_cb(parent_obj) == par_signal_func) {
            //printf("lv_watch_get_parent_obj=%p\n", parent_obj);
            *par_obj = parent_obj;
            break;
        } else {
            parent_obj = lv_obj_get_parent(parent_obj);
        }
    }
}

bool lv_watch_is_activity_one_level(void)
{
    #if USE_LV_WATCH_LAUNCHER2 != 0
    return false;
    #elif USE_LV_WATCH_LAUNCHER != 0
    lv_obj_t * par = lv_scr_act();
    lv_obj_t * obj;

    _LV_LL_READ((par)->child_ll, obj) {
        lv_watch_activity_ext_t * ext = lv_obj_get_ext_attr(obj);
        if(ext == NULL) continue;
        //printf("lv_watch_is_activity_one_level, obj=%p, actId=%d\n", obj, ext->actId);
        if((ext->actId > ACT_ID_ONE_LEVEL_MAX)
           || (ACT_ID_SOS == ext->actId) || (ACT_ID_DIAL_AMBIENT == ext->actId)) {
            return false;
        } else if(!launcher_tileview_act_is_dial() || dial_get_config_state() == 1) {
            return false;
        }
    }

    return true;
    #endif
}

void lv_watch_go_home(void)
{
    sos_destory();
    lv_obj_t * par = lv_scr_act();
    lv_obj_t * obj;

    obj = lv_watch_get_activity_obj(ACT_ID_PHONE);
    if(obj) {
        /*not go home*/
        return;
    }

    obj = lv_watch_get_activity_obj(ACT_ID_VOIPPHONE);
    if(obj) {
        /*not go home*/
        return;
    }

#if USE_LV_WATCH_EXERCISE != 0
    if(exercise_sport_home_key_handle()) {
        return;
    }
#endif

    #if USE_LV_BLUETOOTH != 0
    if(bluetooth_transfer_file_warning()) {
        return;
    }
    #endif

#if USE_LV_WATCH_SD_AUTO_MOUNT != 0
    if(setting_get_release_capture_app_proc()) {
        return;
    } else {
        setting_sd_mount_on_clear_ui();
    }
#endif

    obj = _lv_ll_get_head(&par->child_ll);
    while(obj) {
        lv_watch_activity_ext_t * ext = lv_obj_get_ext_attr(obj);
        if(ext == NULL) {
            obj = _lv_ll_get_next(&par->child_ll, obj);
            continue;
        }

        printf("lv_watch_go_home, obj=%p, actId=%d\n", obj, ext->actId);
        if((ext->actId == ACT_ID_LOWBATTERY) ||
                (ext->actId == ACT_ID_POWER_OFF_CHARGING)
#if USE_LV_WATCH_UPGRADE != 0
                || ((ext->actId == ACT_ID_UPGRADE) && (UGD_STATE_NULL != upgrade_get_state()))
#endif
          ) {
            /*not go home*/
            return;
        }
        if(ext->actId == ACT_ID_LAUNCHER) {
            launcher_power_key_event();
            return;
        }

        if(ext->actId > ACT_ID_ONE_LEVEL_MAX) {
            if(ext->actId == ACT_ID_ALBUM) {
                album_destory(false);
            } else if(NULL != ext->prepare_destory) {
                ext->prepare_destory(obj);
            }
            lv_obj_t * pre_obj = obj;
            obj = _lv_ll_get_next(&par->child_ll, obj);
            ext = lv_obj_get_ext_attr(obj);
            lv_obj_del(pre_obj);
            if(ext == NULL) {
                obj = _lv_ll_get_next(&par->child_ll, obj);
                continue;
            }

            printf("lv_watch_go_home, next actId=%d\n",  ext->actId);
            if(ext->actId == ACT_ID_LAUNCHER) {
                #if USE_LV_WATCH_LAUNCHER != 0
                launcher_power_key_event();
                #endif
                break;
            }
        }
    }

    obj = lv_watch_get_top_activity_obj();
    if(obj == NULL) {
        launcher_activity_create();
    }
}

void lv_watch_go_back(void)
{
    sos_destory();
    if(SOS_GIF_ON == get_sos_status()) {
        return;
    }

    lv_obj_t * obj_phone = lv_watch_get_activity_obj(ACT_ID_PHONE);
    if(obj_phone) {
        return;
    }

    obj_phone = lv_watch_get_activity_obj(ACT_ID_VOIPPHONE);
    if(obj_phone) {
        /*not go back for video call*/
        return;
    }

#if USE_LV_WATCH_EXERCISE != 0
    if(exercise_sport_back_key_handle()) {
        return;
    }
#endif

    #if USE_LV_BLUETOOTH != 0
    if(bluetooth_transfer_file_warning()) {
        return;
    }
    #endif

#if USE_LV_WATCH_SD_AUTO_MOUNT != 0
    if(setting_get_release_capture_app_proc()) {
        return;
    } else {
        setting_sd_mount_on_clear_ui();
    }
#endif

    lv_obj_t * obj = lv_watch_get_top_activity_obj();
    if(obj != NULL) {
        lv_watch_activity_ext_t * ext = lv_obj_get_ext_attr(obj);
        //printf("lv_watch_back, obj=%p, actId=%d\n", obj, ext->actId);
        if((ext->actId == ACT_ID_LOWBATTERY) ||
                (ext->actId == ACT_ID_POWER_OFF_CHARGING)
#if USE_LV_WATCH_UPGRADE != 0
                || ((ext->actId == ACT_ID_UPGRADE) && (UGD_STATE_NULL != upgrade_get_state()))
#endif
          ) {
            /*not go back*/
            return;
        }

        if(ext->actId == ACT_ID_LAUNCHER) {
            launcher_power_key_event();
            return;
        }
        if(ext->actId > ACT_ID_ONE_LEVEL_MAX) {
            if(NULL != ext->prepare_destory) {
                ext->prepare_destory(obj);
            }
            lv_obj_del(obj);
        }
    }
    obj = lv_watch_get_top_activity_obj();
    if(obj == NULL) {
        launcher_activity_create();
    }
}


/* calculate weekday
 * param (in) tm: hal_rtc_t
 * return uint8_t: weekday (sunday = 0)
 */
uint8_t rtc_calc_weekday(hal_rtc_t * tm)
{
    int32_t leapsToDate;
    int32_t lastYear;
    int32_t day;
    int32_t MonthOffset[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };

    if(tm->tm_year < 1753) {
        return 0;
    }

    lastYear = tm->tm_year - 1;

    /*
     * Number of leap corrections to apply up to end of last year
     */
    leapsToDate = lastYear / 4 - lastYear / 100 + lastYear / 400;

    /*
     * This year is a leap year if it is divisible by 4 except when it is
     * divisible by 100 unless it is divisible by 400
     *
     * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 will be
     */
    if((tm->tm_year % 4 == 0) &&
            ((tm->tm_year % 100 != 0) || (tm->tm_year % 400 == 0)) &&
            (tm->tm_mon > 2)) {
        /*
         * We are past Feb. 29 in a leap year
         */
        day = 1;
    } else {
        day = 0;
    }

    day += lastYear * 365 + leapsToDate + MonthOffset[tm->tm_mon - 1] + tm->tm_mday;

    tm->tm_wday = day % 7;

    return(tm->tm_wday);
}

/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
 * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
 * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
 * param (in) tm: hal_rtc_t
 * return uint32_t: time in seconds since 1970
 */
uint32_t time_to_seconds(const hal_rtc_t * tm)
{
    int32_t mon = tm->tm_mon;
    int32_t year = tm->tm_year;
    int32_t days, hours;

    mon -= 2;
    if(0 >= (int32_t)mon) {     /* 1..12 -> 11,12,1..10 */
        mon += 12;      /* Puts Feb last since it has leap day */
        year -= 1;
    }

    days = (unsigned long)(year / 4 - year / 100 + year / 400 +
                           367 * mon / 12 + tm->tm_mday) +
           year * 365 - 719499;
    hours = days * 24 + tm->tm_hour;
    return (hours * 60 + tm->tm_min) * 60 + tm->tm_sec;
}

/* Converts seconds to Gregorian date to seconds since 1970-01-01 00:00:00.
 * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
 * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
 * param (out) tim: INT32 time in seconds
 * param (in) tm: hal_rtc_t  time in date format
 */
void seconds_to_time(int32_t tim, hal_rtc_t * tm)
{
    int32_t  i;
    int32_t  hms, day;

    day = tim / SECDAY;
    hms = tim % SECDAY;

    /* Hours, minutes, seconds are easy */
    tm->tm_hour = hms / 3600;
    tm->tm_min = (hms % 3600) / 60;
    tm->tm_sec = (hms % 3600) % 60;

    /* Number of years in days */
    for(i = STARTOFTIME; day >= DAYS_IN_YEAR(i); i++) {
        day -= DAYS_IN_YEAR(i);
    }
    tm->tm_year = i;

    /* Number of months in days left */
    if(LEAP_YEAR(tm->tm_year)) {
        DAYS_IN_MONTH(FEBRUARY) = 29;
    }
    for(i = 1; day >= DAYS_IN_MONTH(i); i++) {
        day -= DAYS_IN_MONTH(i);
    }
    DAYS_IN_MONTH(FEBRUARY) = 28;
    tm->tm_mon = i;

    /* Days are what is left over (+1) from all that. */
    tm->tm_mday = day + 1;

    rtc_calc_weekday(tm);
}

/**
 * get sim status
 * param (in) void:
 * return bool: 0: sim not present; 1: sim present
*/
uint8_t app_adaptor_get_sim_status_req(void)
{
    return(watch_modem_sim_present_check_req());
}

static void lv_watch_assert_task(lv_task_t * task)
{
    uint32_t * assert = NULL;
    *assert = 1;
}

void lv_watch_assert(void)
{
    lv_task_create(lv_watch_assert_task, 20, LV_TASK_PRIO_HIGH, NULL);
}

void lv_watch_indev_reset(void)
{
    lv_indev_t * indev = lv_indev_get_next(NULL);
    while(indev) {
        if(indev->proc.reset_query) { /*#62332: reset is on going, act_obj has been deleted, refer to lv_obj_del */
            indev = lv_indev_get_next(indev);
            continue;
        }

        if(indev->proc.types.pointer.act_obj
           && lv_obj_is_protected(indev->proc.types.pointer.act_obj, LV_PROTECT_PRESS_LOST)) {
            lv_obj_t * act_obj = indev->proc.types.pointer.act_obj;
            while(act_obj) {
                if(lv_obj_get_signal_cb(act_obj) != lv_watch_obj_signal)
                    act_obj = lv_obj_get_parent(act_obj);
                else break;
            }
            if(act_obj) {
                lv_watch_obj_ext_t * act_obj_ext = lv_obj_get_ext_attr(act_obj);
                if(act_obj_ext && !act_obj_ext->element_click_en) {
                    lv_obj_set_x(act_obj_ext->activity_obj, 0);
                    act_obj_ext->element_click_en = 1;
                    act_obj_ext->drag_hor = 0;
                    act_obj_ext->draging = 0;
                    lv_obj_set_drag(act_obj_ext->activity_obj, true);
                }

                indev->proc.types.pointer.act_obj->signal_cb(indev->proc.types.pointer.act_obj, LV_SIGNAL_PRESS_LOST, indev);
            } else {
                indev = lv_indev_get_next(indev);
                continue;
            }
            lv_indev_reset(indev, NULL);
        }

        indev = lv_indev_get_next(indev);
    }
}

void lv_watch_indev_set_draged(lv_obj_t * obj)
{
    lv_indev_t * indev = lv_indev_get_act();
    if(indev->proc.types.pointer.act_obj == obj)
            indev->proc.types.pointer.drag_in_prog = 1;
}

/**********************
 *   STATIC FUNCTIONS
 **********************/
void lv_watch_set_free_num(lv_obj_t *obj, uint32_t num)
{
    lv_obj_user_data_t *user_data = lv_obj_get_user_data_ptr(obj);
    user_data->user_num = num;
}

void lv_watch_set_free_ptr(lv_obj_t *obj, void *ptr)
{
    lv_obj_user_data_t *user_data = lv_obj_get_user_data_ptr(obj);
    user_data->user_data = ptr;
}

void lv_watch_set_client_ptr(lv_obj_t *obj, void *ptr)
{
    lv_obj_user_data_t *user_data = lv_obj_get_user_data_ptr(obj);
    user_data->user_data_for_client = ptr;
}

uint32_t lv_watch_get_free_num(lv_obj_t *obj)
{
    lv_obj_user_data_t *user_data = lv_obj_get_user_data_ptr(obj);
    return user_data->user_num;
}

void * lv_watch_get_free_ptr(lv_obj_t *obj)
{
    lv_obj_user_data_t *user_data = lv_obj_get_user_data_ptr(obj);
    return user_data->user_data;
}

/* signal function for change sel font size */
static lv_res_t lv_watch_roller_scrl_signal(lv_obj_t * roller_scrl, lv_signal_t sign, void * param)
{
    lv_res_t res = LV_RES_OK;

    /* Include the ancient signal function */
    res = ancestor_scrl_signal(roller_scrl, sign, param);
    if(res != LV_RES_OK) return res;

    lv_obj_t * roller = lv_obj_get_parent(roller_scrl);
    if(lv_roller_get_option_cnt(roller) == 0) return LV_RES_INV;    /*On delete the ddlist signal deletes the label so nothing left to do here*/

    if(sign == LV_SIGNAL_PRESSED) {
        lv_obj_t * om = lv_obj_get_parent(roller);
        lv_obj_t * par = lv_obj_get_parent(om);
        lv_obj_set_parent(roller, par);
        lv_obj_set_hidden(om, true);
        printf("delete om\n");
    } else if(sign == LV_SIGNAL_DRAG_END) {
        lv_obj_t * par = lv_obj_get_parent(roller);
        lv_obj_t * om = lv_obj_get_child_back(par, NULL);
        lv_obj_set_parent(roller, om);
        lv_obj_align(roller, NULL, LV_ALIGN_CENTER, 0, 0);
        lv_obj_set_hidden(om, false);

        char * sel_str = (char *)lv_obj_get_style_value_str(om, LV_STATE_DEFAULT);
        lv_roller_get_selected_str(roller, sel_str, 6);
    } else if((sign == LV_SIGNAL_RELEASED) || (sign == LV_SIGNAL_PRESS_LOST)) {
        lv_indev_t * indev = lv_indev_get_act();
        if(!lv_indev_is_dragging(indev)) {
            lv_obj_t * par = lv_obj_get_parent(roller);
            lv_obj_t * om = lv_obj_get_child_back(par, NULL);
            lv_obj_set_parent(roller, om);
            lv_obj_align(roller, NULL, LV_ALIGN_CENTER, 0, 0);
            lv_obj_set_hidden(om, false);

            char * sel_str = (char *)lv_obj_get_style_value_str(om, LV_STATE_DEFAULT);
            lv_roller_get_selected_str(roller, sel_str, 6);
        }
    }

    return res;
}

/* function for change sel font size */
void lv_watch_roller_set_sel_style(lv_obj_t *roller, char * str)
{
    lv_obj_t * scrl = lv_page_get_scrl(roller);
    ancestor_scrl_signal = lv_obj_get_signal_cb(scrl);
    lv_obj_set_signal_cb(scrl, lv_watch_roller_scrl_signal);

    lv_obj_t * par = lv_obj_get_parent(roller);
    lv_obj_t * om = lv_objmask_create(par, NULL);
    lv_obj_set_size(om, lv_obj_get_width(par), lv_obj_get_height(par));
    lv_obj_align(om, NULL, LV_ALIGN_CENTER, 0 , 0);
    lv_obj_set_parent(roller, om);
    lv_obj_align(roller, NULL, LV_ALIGN_CENTER, 0, 0);

    //get row count
    const lv_font_t * font = lv_obj_get_style_text_font(roller, LV_ROLLER_PART_BG);
    lv_style_int_t line_space = lv_obj_get_style_text_line_space(roller, LV_ROLLER_PART_BG);
    uint8_t row_cnt = lv_obj_get_height(roller) / (lv_font_get_line_height(font) + line_space);

    //get mask area
    lv_area_t a;
    a.x1 = lv_obj_get_x(om);
    a.y1 = lv_obj_get_y(om) + lv_obj_get_height(om) / 2 - lv_obj_get_height(om) / row_cnt / 2;
    a.x2 = lv_obj_get_x(om) + lv_obj_get_width(om);
    a.y2 = lv_obj_get_y(om) + lv_obj_get_height(om) / 2 + lv_obj_get_height(om) / row_cnt / 2;

    //init mask from area above
    lv_draw_mask_radius_param_t r1;
    lv_draw_mask_radius_init(&r1, &a, 0, true);
    lv_objmask_add_mask(om, &r1);

    //set sel str
    lv_obj_set_style_local_value_font(om, LV_OBJMASK_PART_MAIN, LV_STATE_DEFAULT, &lv_font_montserrat_24);
    lv_obj_set_style_local_value_color(om, LV_OBJMASK_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE);
    lv_obj_set_style_local_value_str(om, LV_OBJMASK_PART_MAIN, LV_STATE_DEFAULT, str);
    char * sel_str = (char *)lv_obj_get_style_value_str(om, LV_STATE_DEFAULT);
    lv_roller_get_selected_str(roller, sel_str, 6);

    printf("create om\n");
}

/* function for change sel font size */
void lv_watch_img_common_signal(lv_obj_t * img, lv_signal_t sign, void * param)
{
    if(sign == LV_SIGNAL_CLEANUP) {
        lv_img_ext_t * ext = lv_obj_get_ext_attr(img);
        if(ext->src_type == LV_IMG_SRC_FILE || ext->src_type == LV_IMG_SRC_SYMBOL) {
            lv_mem_free(ext->src);
            ext->src      = NULL;
            ext->src_type = LV_IMG_SRC_UNKNOWN;
        }
    }
}

void lv_watch_set_wallpaper(lv_obj_t * obj)
{
#if WATCH_HAS_WALLPAPER
    lv_obj_t * img = lv_img_create(obj, NULL);
    LV_ASSERT_MEM(img);
    lv_img_set_src(img, watch_get_bg());
    lv_obj_set_size(img, LV_HOR_RES, LV_VER_RES);
#endif
}


#endif /*USE_LV_WATCH_COMMON*/
